﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Kristall
{
    public class Camera2D
    {
        public Matrix World
        {
            get
            {
                return Matrix.CreateTranslation(-_position.X, -_position.Y, 0) * 
                    Matrix.CreateScale(new Vector3(Scale, Scale, 1f)) * 
                    Matrix.CreateTranslation(Kristall.Viewport.X * 0.5f, Kristall.Viewport.Y * 0.5f, 0);
            }
        }


        public bool CenterOnPosition { get; set; }

        private Vector2 _position = Vector2.Zero;
        public Vector2 TargetPosition = Vector2.Zero;

        public Vector2 Velocity = Vector2.Zero;

        public float Mass
        {
            get
            {
                return Kristall.Options.camera_mass;
            }
        }

        private float damping = 600.0f;
        private float stiffness = 1800.0f;

        public bool Spring
        {
            get
            {
                return Kristall.Options.camera_spring;
            }
            set
            {
                Kristall.Options.camera_spring = value;
            }
        }

        public float Scale
        {
            get
            {
                return Kristall.Options.camera_scale;
            }
        }

        public Camera2D()
        {
            CenterOnPosition = true;
        }

        public void Update(Vector2 position, float dt)
        {
            if (Spring)
            {
                TargetPosition = position;

                // Calculate spring force
                Vector2 stretch = _position - TargetPosition;
                Vector2 force = -stiffness * stretch - damping * Velocity;

                // Apply acceleration
                Vector2 acceleration = force / Mass;
                Velocity += acceleration * dt;

                // Apply velocity
                _position += Velocity * dt;
            }
            else
            {
                this._position = position;
            }
        }

        public void SetPosition(Vector2 position)
        {
            this._position = position;
        }

        internal Vector2 ScreenToWorld(Vector2 screenPosition)
        {
            return Vector2.Transform(screenPosition, Matrix.Invert(this.World));
        }


        internal Vector2 WorldToScreen(Vector2 worldPosition)
        {
            return Vector2.Zero;
        }

        internal Vector2 GetPosition()
        {
            return _position;
        }
    }
}
